package JianZhiOffer;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 请实现一个函数用来判断字符串是否表示数值（包括整数和小数）。
 * 例如，字符串"+100"、"5e2"、"-123"、"3.1416"、"0123"都表示数值，
 * 但"12e"、"1a3.14"、"1.2.3"、"+-5"、"-1E-16"及"12e+5.4"都不是。
 * */
class Solution20 {


    /**
     * 逻辑判断
     * */
    public boolean isNumber1(String s) {
        if(s == null || s.length() == 0){
            return false;
        }
        //标记是否遇到相应情况
        boolean numSeen = false;
        boolean dotSeen = false;
        boolean eSeen = false;
        char[] str = s.trim().toCharArray();
        for(int i = 0;i < str.length; i++){
            if(str[i] >= '0' && str[i] <= '9'){
                numSeen = true;
            }else if(str[i] == '.'){
                //.之前不能出现.或者e
                if(dotSeen || eSeen){
                    return false;
                }
                dotSeen = true;
            }else if(str[i] == 'e' || str[i] == 'E'){
                //e之前不能出现e，必须出现数
                if(eSeen || !numSeen){
                    return false;
                }
                eSeen = true;
                numSeen = false;//重置numSeen，排除123e或者123e+的情况,确保e之后也出现数
            }else if(str[i] == '-' || str[i] == '+'){
                //+-出现在0位置或者e/E的后面第一个位置才是合法的
                if(i != 0 && str[i-1] != 'e' && str[i-1] != 'E'){
                    return false;
                }
            }else{//其他不合法字符
                return false;
            }
        }
        return numSeen;
    }


    /**
     * 状态机
     * */
    public boolean isNumber(String s) {
        int[][] stateTable = {{1, 2, 7, -1, -1, 0},
                {-1, 2, 7, -1, -1, -1},
                {-1, 2, 3, 4, -1, 9},
                {-1, 3, -1, 4, -1, 9},
                {6, 5, -1, -1, -1, -1},
                {-1, 5, -1, -1, -1, 9},
                {-1, 5, -1, -1, -1, -1},
                {-1, 8, -1, -1, -1, -1},
                {-1, 8, -1, 4, -1, 9},
                {-1, -1, -1, -1, -1, 9}
        };
        Map<String, Integer> col = new HashMap<String, Integer>() {
            {
                put("sign", 0);
                put("number", 1);
                put(".", 2);
                put("exp", 3);
                put("other", 4);
                put("blank", 5);
            }
        };
        int state = 0;
        List<Integer> legalState = new ArrayList<Integer>() {{
            add(2);
            add(3);
            add(5);
            add(8);
            add(9);
        }};
        for (int i = 0; i < s.length(); i++) {
            state = stateTable[state][col.get(getCol(s.charAt(i)))];
            if (state == -1) return false;
        }
        if (legalState.contains(state)) return true;
        return false;

    }

    public String getCol(char c) {
        if (c == '+' || c == '-') return "sign";
        if (c >= '0' && c <= '9') return "number";
        if (c == '.') return ".";
        if (c == 'E' || c == 'e') return "exp";
        if (c == ' ') return "blank";
        return "other";
    }
}